package aapt

import (
	"strconv"
	"strings"

	"notabug.org/Umnik/GoAndroidSDK/v2/components/misc"
)

// ParseAppInfoDumpFromBytes returns AppInfo from raw input bytes
func ParseAppInfoDumpFromBytes(rawOutput []byte) AppInfo {
	return ParseAppInfoDumpFromString(string(rawOutput))
}

// ParseAppInfoDumpFromString returns AppInfo from raw input string
func ParseAppInfoDumpFromString(stringOutput string) AppInfo {
	appInfoResult := AppInfo{
		AppLabel:    map[string]string{},
		NativeCode:  map[string]struct{}{},
		MetaData:    map[string]string{},
		IsSplitBase: false,
	}

	for _, rawLine := range strings.Split(stringOutput, "\n") {
		rawLine = strings.TrimSpace(rawLine)

		switch {
		case strings.HasPrefix(rawLine, "package:"):
			values := processPackageLine(rawLine)
			appInfoResult.PackageName = values[0]
			appInfoResult.VersionCode = misc.IntExtractor(values[1])
			appInfoResult.VersionName = values[2]

		case strings.HasPrefix(rawLine, "sdkVersion"):
			appInfoResult.MinSDKVersion = misc.IntExtractor(misc.TwoSpotRexValue(misc.RemoveQuoteMark(rawLine)))

		case strings.HasPrefix(rawLine, "targetSdkVersion"):
			appInfoResult.TargetSDKVersion = misc.IntExtractor(misc.TwoSpotRexValue(misc.RemoveQuoteMark(rawLine)))

		case strings.HasPrefix(rawLine, "uses-permission: name="):
			if strings.Contains(rawLine, "android.permission.") {
				appInfoResult.UsesAndroidPermission = append(
					appInfoResult.UsesAndroidPermission, extractPermission(rawLine),
				)
			} else {
				appInfoResult.UsesCustomPermission = append(
					appInfoResult.UsesCustomPermission, extractPermission(rawLine),
				)
			}

		case strings.HasPrefix(rawLine, "application-label"):
			key, value := extractLabel(rawLine)
			appInfoResult.AppLabel[key] = value

		case strings.HasPrefix(rawLine, "launchable-activity"):
			appInfoResult.LaunchActivity = append(appInfoResult.LaunchActivity, extractLaunchActivity(rawLine))

		case strings.HasPrefix(rawLine, "native-code"):
			appInfoResult.NativeCode = extractNativeCode(rawLine)

		case strings.HasPrefix(rawLine, "application-debuggable"):
			appInfoResult.Debuggable = true

		case strings.HasPrefix(rawLine, "testOnly="):
			appInfoResult.TestOnly = true

		case strings.HasPrefix(rawLine, "meta-data:"):
			res := extractMetaData(rawLine)
			appInfoResult.MetaData[res[0]] = res[1]
			if res[0] == "com.android.vending.splits.required" {
				appInfoResult.IsSplitBase = true
			}
		}
	}

	return appInfoResult
}

// ParseDumpResourcesFromBytes returns Resources from raw input bytes
func ParseDumpResourcesFromBytes(rawOutput []byte) Resources {
	return ParseDumpResourcesFromString(string(rawOutput))
}

// ParseDumpResourcesFromString returns Resources from raw input string
func ParseDumpResourcesFromString(stringOutput string) Resources {
	out := strings.Split(stringOutput, "\n")
	resourcesResult := Resources{
		Array:  map[string][][2]string{},
		String: map[string][][2]string{},
	}

	last := 0
	for i, line := range out {
		if i < last {
			continue
		}
		line = strings.TrimSpace(line)
		if !strings.HasPrefix(line, "resource") {
			continue
		}
		if strings.Contains(line, "android:array/") {
			val, err := strconv.Atoi(strings.SplitN(out[i+1], "=", 4)[3])
			if err != nil {
				panic(err)
			}
			last = i + val + 2
			resourcesResult.Array[resArrName(line)] = resArrValues(out[i+2 : last])
			continue
		}
		if strings.Contains(line, "android:string/") {
			paramName := resStringName(line)
			last = i + 1
			resourcesResult.String[paramName] = append(resourcesResult.String[paramName], resStringValue(out[last]))
			continue
		}
	}

	return resourcesResult
}
